﻿@page "/GridCascadingEditors"
<div class="demo-description mw-1100">
    <h2><DemoNavLink Link="GridEditData#CascadingEditors" />Cascading Editors</h2>

    <p>
        This module illustrates <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxComboBox-2#cascading-comboboxes">cascade comboboxes</a>: <b>City</b> and <b>Region</b>.
        These comboboxes are displayed when you edit a grid row.
        The <b>City</b> combobox is dynamically populated with city names based on the value selected in the <b>Region</b> combobox.
    </p>

    <p>
        Both the Region and City columns use the <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxDataGridColumn.EditTemplate">EditTemplate context</a> cast to the <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext">CellEditContext</a> type that contains:
    </p>

    <ul>
        <li>
            An original cell value as a <b>DataItem</b> object.
        </li>
        <li>
            An <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.EditedValues">EditedValues</a> dictionary with changed cell values.
        </li>
        <li>
            A <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.CellValue">CellValue</a> object that stores the current cell’s value.
        </li>
        <li>
            Two overloads of the <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.OnChanged(System.Object)">OnChanged</a> method that allow one combobox to respond to another combobox’s value change.
        </li>
        <li>
            The <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.GetEditorValue(System.String)">GetEditorValue</a> method that returns a value of any grid cell.
        </li>
    </ul>

    <p>
        Click <b>Edit</b> to see how the <b>Region</b> and <b>City</b> comboboxes communicate using the <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.OnChanged(System.Object)">OnChanged</a> and <a class="helplink" target="_blank" href="https://docs.devexpress.com/Blazor/DevExpress.Blazor.CellEditContext.GetEditorValue(System.String)">GetEditorValue</a> methods to pass/get values to/from each other.
    </p>
</div>

@if (Vacancies == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <DxDataGrid Data="@Vacancies"
                ShowPager="false"
                RowRemoving="@((dataItem) => OnRowRemoving(dataItem))"
                RowInserting="@((newValues) => OnRowInserting(newValues))"
                RowUpdating="@((updatingDataItem, newValues) => OnRowUpdating(updatingDataItem, newValues))"
                CssClass="mw-1100">
        <DxDataGridCommandColumn Width="150px"></DxDataGridCommandColumn>

        <DxDataGridComboBoxColumn Field="@nameof(Vacancy.Region)" Data="@VacancyRepository.Regions">
            <EditTemplate>
                @{
                    var editingContext = (CellEditContext)context;
                    var region = (string)editingContext.GetEditorValue(nameof(Vacancy.Region));
                }
                <DxComboBox Data="@VacancyRepository.Regions"
                            NullText="Select Region..."
                            Value="@region"
                            ValueChanged="@(EventCallback.Factory.Create(this, (string newCellValue) => {
                                                editingContext.OnChanged(newCellValue);
                                                editingContext.OnChanged(nameof(Vacancy.City), null);
                                                }))">
                </DxComboBox>
            </EditTemplate>
        </DxDataGridComboBoxColumn>
        <DxDataGridColumn Field="@nameof(Vacancy.City)">
            <EditTemplate>
                @{
                    var editingContext = (CellEditContext)context;

                    var region = (string)editingContext.GetEditorValue(nameof(Vacancy.Region));
                    var city = ((string)(editingContext.GetEditorValue(nameof(Vacancy.City))));

                    var cities = VacancyRepository.GetOfficeLocationsByRegion(region).Select(x => x.City);
                }
                <DxComboBox Data="@cities"
                            NullText="Select City..."
                            Text="@city"
                            ValueChanged="@(EventCallback.Factory.Create(this, (string newCellValue) => editingContext.OnChanged(newCellValue)))">
                </DxComboBox>
            </EditTemplate>
        </DxDataGridColumn>
        <DxDataGridColumn Field="@nameof(Vacancy.Description)" Caption="Vacancy"></DxDataGridColumn>
    </DxDataGrid>
}

<CodeSnippet_GridCascadingEditors></CodeSnippet_GridCascadingEditors>

@code {
    IEnumerable<Vacancy> Vacancies;

    protected override async Task OnInitializedAsync()
    {
        Vacancies = await VacancyRepository.GetVacancies(3);
    }

    public void OnRegionChanged()
    {
        InvokeAsync(StateHasChanged);
    }
    void OnRowUpdating(Vacancy vacancy, Dictionary<string, object> newValue)
    {
        foreach (var field in newValue.Keys)
        {
            switch (field)
            {
                case "Description":
                    vacancy.Description = (string)newValue[field];
                    break;
                case "Region":
                    vacancy.Region = (string)newValue[field];
                    break;
                case "City":
                    vacancy.City = (string)newValue[field];
                    break;
            }
        }
    }
    void OnRowRemoving(Vacancy vacancy)
    {
        Vacancies = Vacancies.Where(v => v != vacancy).ToArray();
        InvokeAsync(StateHasChanged);
    }
    void OnRowInserting(Dictionary<string, object> newValue)
    {
        var newVacancy = new Vacancy();
        OnRowUpdating(newVacancy, newValue);
        Vacancies = (new Vacancy[] { newVacancy }).Concat(Vacancies);

        InvokeAsync(StateHasChanged);
    }
}
